home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / BARNET / ARMTEX / RAFS115 / rafsln / rafsln.c < prev    next >
C/C++ Source or Header  |  1998-11-13  |  10KB  |  362 lines

  1. /*
  2.   __   _
  3.   |_) /|  Copyright Richard Atterer
  4.   | \/¯|  <atterer@augsburg.baynet.de>
  5.   ¯ ´` ¯
  6.   Create symbolic links to the files inside a raFS disc.
  7.   Syntax: *rafsln [switches] <DirContaining!Atterer> [ <DestinationDir> ]
  8.   A directory with the disc name will be created in the destination
  9.   directory (whose name defaults to . if not specified).
  10.  
  11.   V1.01  13-11-98
  12. */
  13.  
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <errno.h>
  17. #include <fcntl.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <unistd.h>
  22.  
  23. #define maxextlen 23
  24.  
  25. #ifdef DEBUG
  26.   #define D(cmd) cmd
  27.   #define ND(cmd)
  28.   #define log(args) printf args;
  29. #else
  30.   #define D(cmd)
  31.   #define ND(cmd) cmd
  32.   #define log(args)
  33. #endif
  34.  
  35. typedef unsigned char  u8;
  36. typedef unsigned int   u32;
  37. typedef unsigned short u16;
  38.  
  39. typedef enum boolean { FALSE, TRUE } boolean;
  40.  
  41. /* the following is for little endian */
  42. typedef u32 rafs_id;
  43. #define level1rafsdir(id) (id & 0xff)
  44. #define level2rafsdir(id) ((id >> 8) & 0xff)
  45. #define level3rafsdir(id) ((id >> 16) & 0xff)
  46.  
  47. #define DIRSEP "/"
  48. #define DIRSEP_CHAR '/'
  49. #define FILESEP "."
  50. #define FILESEP_CHAR '.'
  51.  
  52. typedef struct rafs_dir_s {
  53.   u32 entries;
  54.   u32 unused_m;
  55.   u32 parent_id;
  56.   u32 unused_pp;
  57.   u32 offset[1];
  58. } rafs_dir;
  59.  
  60. typedef struct rafs_direntry_s {
  61.   u32 load, exec;
  62.   u32 length;
  63.   u32 attr;
  64.   u32 rafs_flags;
  65.   u32 unused_bf;
  66.   u32 id;
  67.   char name[1];
  68. } rafs_direntry;
  69.  
  70. void syntaxerror(void);
  71. void rafs_readmapping();
  72. void rafs_deletemapping();
  73. int link_rafs_disc(const char* source, const char* destination);
  74. int link_rafs_dir(char* src, int srclen, char* dst, int dstlen, rafs_id id);
  75. void append_rafs_id(char* buf, rafs_id id);
  76. int filename_conv(char* buf, const rafs_direntry* riscos);
  77.  
  78. static char* ext[4096];
  79. static const char mappingsfile[] = "/.rafsln_mapping"; /* in home dir */
  80.  
  81. static boolean symlinks = FALSE; /* create symbolic, not hard links */
  82. /* add extensions to RiscOS files without any '/' in their names */
  83. static boolean extensions = FALSE;
  84. /* add hex filetype after comma, e.g. 'filename,fff'. If both extensions
  85.    and this are true, hex filetypes are only added for files for which
  86.    there is no type->extension mapping */
  87. static boolean commatype = FALSE;
  88.  
  89.  
  90. int main(int argc, char* argv[])
  91. {
  92.   char* source = 0;
  93.   char* destination = 0;
  94.  
  95.   /* scan command line arguments */
  96.   while (--argc) {
  97.     if (strcmp(*++argv, "-s") == 0 && symlinks == FALSE)
  98.       symlinks = TRUE;
  99.     else if (strcmp(*argv, "-e") == 0 && extensions == FALSE)
  100.       extensions = TRUE;
  101.     else if (strcmp(*argv, "-c") == 0 && commatype == FALSE)
  102.       commatype = TRUE;
  103.     else if (source == 0)
  104.       source = *argv;
  105.     else if (destination == 0)
  106.       destination = *argv;
  107.     else
  108.       syntaxerror();
  109.   }
  110.   if (source == 0) syntaxerror();
  111.   if (destination == 0) destination = ".";
  112.  
  113.   if (extensions) rafs_readmapping();
  114.   if (link_rafs_disc(source, destination)) {
  115.     if (extensions) rafs_deletemapping();
  116.     perror("rafsln");
  117.     exit(1);
  118.   }
  119.   if (extensions) rafs_deletemapping();
  120.   return 0;
  121. }
  122.  
  123. void syntaxerror(void)
  124. {
  125.   fprintf(stderr, "Syntax: rafsln [-s] [-e] [-c] <DirContaining!Atterer> "
  126.       "[<DestinationDir>]\n"
  127.       "Creates a directory with the name of the raFS disc, filled with "
  128.       "links.\n"
  129.       "  -s  Make symbolic links instead of hard links\n"
  130.       "  -e  Add extensions to names not containing any dots\n"
  131.       "  -c  Add filetype after comma; 'filename,fff'\n");
  132.   exit(1);
  133. }
  134.  
  135. /* read contents of RiscOS -> extension mappings
  136.    the mappings are stored in ext[] */
  137. void rafs_readmapping()
  138. {
  139.   int read, type;
  140.   char extstr[maxextlen];
  141.   char filename[1024];
  142.   FILE* map;
  143.   char* home;
  144.   
  145.   home = getenv("HOME");
  146.   if (home == 0)
  147.     filename[0] = '\0';
  148.   else
  149.     strcpy(filename, home);
  150.   strcpy(filename + strlen(filename), mappingsfile);
  151.  
  152.   map = fopen(filename, "r");
  153.   if (map == 0) {
  154.     fprintf(stderr, "rafsln: Couldn't open '%s'\n", filename);
  155.     exit(1);
  156.   }
  157.   while ((read = fscanf(map, " %x %s \n", &type, extstr)) == 2) {
  158.     int extlen = strlen(extstr);
  159.     ext[type] = (char*)malloc(extlen + 1);
  160.     memcpy(ext[type], extstr, extlen + 1);
  161.     log(("rafs_readmapping: %x is %s\n", type, ext[type]));
  162.   }
  163.   fclose(map);
  164.   return;
  165. }
  166.  
  167. /* free memory claimed by extension mappings */
  168. void rafs_deletemapping()
  169. {
  170.   int i;
  171.   for (i = 0; i < 4096; i++)
  172.     if (ext[i]) free(ext[i]);
  173.   return;
  174. }
  175.  
  176. /* Create links to the files inside a raFS dir structure.
  177.    Returns 0 for success, else -1 and errno set */
  178. int link_rafs_disc(const char* source, const char* destination)
  179. {
  180.   int err;
  181.   int srclen = strlen(source);
  182.   int dstlen = strlen(destination);
  183.   char* src;
  184.   char* dst;
  185.   FILE* att;
  186.  
  187.   /* claim memory */
  188.   src = (char*)malloc(srclen + 10);  /* appending "/!atterer0" */
  189.   if (src == 0) return -1;
  190.   strcpy(src, source);
  191.   dst = (char*)malloc(dstlen + 64 + 256);
  192.   if (dst == 0) {
  193.     free(src);
  194.     return -1;
  195.   }
  196.   strcpy(dst, destination);
  197.  
  198.   /* append '/' unless already present */
  199.   if (src[srclen - 1] != DIRSEP_CHAR)
  200.     src[srclen++] = DIRSEP_CHAR;
  201.   if (dst[dstlen - 1] != DIRSEP_CHAR)
  202.     dst[dstlen++] = DIRSEP_CHAR;
  203.  
  204.   /* open !Atterer, get disc name */
  205.   strcpy(src + srclen, "!Atterer");
  206.   log(("link_rafs_disc: open %s\n", src));
  207.   att = fopen(src, "r");
  208.   if (att == 0 || fread(dst + dstlen, sizeof(u8), 64, att) != 64) {
  209.     free (src); free(dst);
  210.     return -1;
  211.   }
  212.   fclose(att);
  213.  
  214.   /* create dir with disc name */
  215.   log(("link_rafs_disc: create %s\n", dst));
  216.   if (mkdir(dst,
  217.         S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) {
  218.     free (src); free(dst);
  219.     return -1;
  220.   }
  221.   dstlen = strlen(dst);
  222.   dst[dstlen++] = DIRSEP_CHAR;
  223.  
  224.   /* recurse through raFS directory structure */
  225.   err = link_rafs_dir(src, srclen, dst, dstlen, (rafs_id)0);
  226.   free(src); free(dst);
  227.   if (err) return -1; else return 0;
  228. }
  229.  
  230. /* Will append e.g. "A0/A0/A0" after srclen bytes.
  231.    Will append e.g. "DirName/WheeLongFileName" after dstlen bytes
  232.    id is the ID of a directory */
  233. int link_rafs_dir(char* src, int srclen, char* dst, int dstlen, rafs_id id)
  234. {
  235.   rafs_dir* dir;
  236.   struct stat statbuf;
  237.   unsigned i;
  238.   FILE* dirhandle;
  239.   int err = 0;
  240.  
  241.   append_rafs_id(src + srclen, id);
  242.  
  243.   if (stat(src, &statbuf)) return -1;
  244.   dir = (rafs_dir*)malloc(statbuf.st_size);
  245.   if (dir == 0) return -1;
  246.  
  247.   if ((dirhandle = fopen(src, "r")) == 0) {
  248.     free(dir);
  249.     return -1;
  250.   }
  251.   fread(dir, 1, statbuf.st_size, dirhandle); /* load dir data */
  252.   if (ferror(dirhandle)) {
  253.     free(dir);
  254.     return -1;
  255.   }
  256.   fclose(dirhandle);
  257.   log(("link_rafs_dir: dir %s, %d entries\n", src, dir->entries));
  258.   
  259.   /* will continue after errors during the recursion */
  260.   for (i = 0; i < dir->entries; i++) {
  261.     rafs_direntry* entry =
  262.       (rafs_direntry*)(&dir->offset + dir->offset[i] / sizeof(u32));
  263.     filename_conv(dst + dstlen, entry);
  264.     if ((entry->rafs_flags & 0xc0) == 0xc0) {
  265.       int newlen = dstlen + strlen(dst + dstlen);
  266.       /* directory */
  267.       if (mkdir(dst, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
  268.         | S_IROTH | S_IWOTH)) err = -1;
  269.       dst[newlen++] = DIRSEP_CHAR;
  270.       dst[newlen] = '\0';
  271.       if (link_rafs_dir(src, srclen, dst, newlen, entry->id) != 0)
  272.     err = -1;
  273.     } else {
  274.       /* file - create link */
  275.       int(*linkfct)(const char* oldpath, const char* newpath);
  276.       append_rafs_id(src + srclen, entry->id);
  277.       log(("link_rafs_dir: %s -> %s\n", dst, src));
  278.       if (symlinks) linkfct = &symlink; else linkfct = &link;
  279.       if (linkfct(src, dst)) err = -1;
  280.     }
  281.   }
  282.   free(dir);
  283.   return err;
  284. }
  285.  
  286. void append_rafs_id(char* buf, rafs_id id)
  287. {
  288.   static const char* names =
  289.     "A0" DIRSEP "\0A1" DIRSEP "\0A2" DIRSEP "\0"
  290.     "B0" DIRSEP "\0B1" DIRSEP "\0B2" DIRSEP "\0"
  291.     "C0" DIRSEP "\0C1" DIRSEP "\0C2" DIRSEP "\0"
  292.     "D0" DIRSEP "\0D1" DIRSEP "\0D2" DIRSEP "\0"
  293.     "E0" DIRSEP "\0E1" DIRSEP "\0E2" DIRSEP "\0"
  294.     "F0" DIRSEP "\0F1" DIRSEP "\0F2" DIRSEP "\0"
  295.     "G0" DIRSEP "\0G1" DIRSEP "\0G2" DIRSEP "\0"
  296.     "H0" DIRSEP "\0H1" DIRSEP "\0H2" DIRSEP "\0"
  297.     "I0" DIRSEP "\0I1" DIRSEP "\0I2" DIRSEP "\0"
  298.     "J0" DIRSEP "\0J1" DIRSEP "\0J2" DIRSEP "\0"
  299.     "K0" DIRSEP "\0K1" DIRSEP "\0K2" DIRSEP "\0"
  300.     "L0" DIRSEP "\0L1" DIRSEP "\0L2" DIRSEP "\0"
  301.     "M0" DIRSEP "\0M1" DIRSEP "\0M2" DIRSEP "\0"
  302.     "N0" DIRSEP "\0N1" DIRSEP "\0N2" DIRSEP "\0"
  303.     "O0" DIRSEP "\0O1" DIRSEP "\0O2" DIRSEP "\0"
  304.     "P0" DIRSEP "\0P1" DIRSEP "\0P2" DIRSEP "\0"
  305.     "Q0" DIRSEP "\0Q1" DIRSEP "\0Q2" DIRSEP "\0"
  306.     "R0" DIRSEP "\0R1" DIRSEP "\0R2" DIRSEP "\0"
  307.     "S0" DIRSEP "\0S1" DIRSEP "\0S2" DIRSEP "\0"
  308.     "T0" DIRSEP "\0T1" DIRSEP "\0T2" DIRSEP "\0"
  309.     "U0" DIRSEP "\0U1" DIRSEP "\0U2" DIRSEP "\0"
  310.     "V0" DIRSEP "\0V1" DIRSEP "\0V2" DIRSEP "\0"
  311.     "W0" DIRSEP "\0W1" DIRSEP "\0W2" DIRSEP "\0"
  312.     "X0" DIRSEP "\0X1" DIRSEP "\0X2" DIRSEP "\0"
  313.     "Y0" DIRSEP "\0Y1" DIRSEP "\0Y2" DIRSEP "\0"
  314.     "Z0" DIRSEP "\0Z1" DIRSEP "\0";
  315.   const char* cur;
  316.  
  317.   cur = names + level1rafsdir(id) * 4;
  318.   *buf++ = *cur++; *buf++ = *cur++; *buf++ = *cur++;
  319.   cur = names + level2rafsdir(id) * 4;
  320.   *buf++ = *cur++; *buf++ = *cur++; *buf++ = *cur++;
  321.   cur = names + level3rafsdir(id) * 4;
  322.   *buf++ = *cur++; *buf++ = *cur++; *buf++ = '\0';
  323.  
  324.   return;
  325. }
  326.  
  327. /* conversion of RiscOS name to other OS
  328.    returns nr of characters in output name */
  329. int filename_conv(char* buf, const rafs_direntry* riscos)
  330. {
  331.   char* ptr = buf;
  332.   const char* riscos_name = riscos->name;
  333.   char c;
  334.   int filetype;
  335.   boolean noextension = TRUE;
  336.  
  337.   while ((c = *riscos_name++) != 0) {
  338.     if (c == '.' || c == '/') {
  339.       c ^= '.' ^ '/';
  340.       noextension = FALSE;
  341.     }
  342.     else if (c == '$' || c == '<') c ^= '$' ^ '<';
  343.     *ptr++ = c;
  344.   }
  345.  
  346.   if ((riscos->rafs_flags & 0xc0) != 0xc0 /* only for files */
  347.       && (riscos->load & 0xfff00000) == 0xfff00000) {
  348.     filetype = (riscos->load & 0xfff00) >> 8;
  349.     if (extensions && noextension && ext[filetype]) {
  350.       *ptr++ = FILESEP_CHAR;
  351.       strcpy(ptr, ext[filetype]);
  352.       ptr += strlen(ptr);
  353.       noextension = FALSE;
  354.     }
  355.     if (commatype && (!extensions || (extensions && noextension))) {
  356.       ptr += sprintf(ptr, ",%03x", filetype);
  357.     }
  358.   }
  359.   *ptr = 0;
  360.   return ptr - buf;
  361. }
  362.